#include <typedefs.h>

U_INT32 QuadWordMultiplyDivide ( U_INT32 multiplicand,
                                 U_INT32 multiplier,
                                 U_INT32 divisor )
{

/* identical to return round( multiplicand*multiplier/divisor )
    however, this uses a 64 bit intermediate */

/* according to the 68332 C Cross Compiler Reference Manual
   Section 3, page 3-18 (Register Usage)  D0,D1 are reserved
   for working registers, we can scribble them at will.  This
   section also indicates that D0 is used for a 32 bit return. */
U_INT32 temp = multiplicand*multiplier/divisor;
//printf("%d * %d / %d = %d\n",multiplicand,multiplier,divisor,temp);
return temp;
#ifndef mccabe
#pragma ASM

        tst.l   (S_divisor,A6)
        bne     QWMD_Start

        move.l  #-1,d1
        bra     QWMD_Done

QWMD_Start
	move.l	(S_multiplicand,A6),D1
	mulu.l	(S_multiplier,A6),D0:D1
	divu.l	(S_divisor,A6),D0:D1
        add.l   D0,D0                  ; mult remainder by 2
        divu.l  (S_divisor,A6),D0      ; divide, yeilding only quotient
        add.l   D1,D0                  ; round 

QWMD_Done
	move.l	d1,-(sp)               ; push result for debug reasons
	move.l	(sp)+,d1               ; pop it back off


#pragma END_ASM
#endif
        
  (void)multiplicand;
  (void)multiplier;
  (void)divisor;
}


INT32 SignedQuadWordMultiplyDivide ( INT32 multiplicand,
                                     U_INT32 multiplier,
                                     U_INT32 divisor )
{

/* identical to return ( multiplicand*multiplier/divisor )
    however, this uses a 64 bit intermediate */

/* according to the 68332 C Cross Compiler Reference Manual
   Section 3, page 3-18 (Register Usage)  D0,D1 are reserved
   for working registers, we can scribble them at will.  This
   section also indicates that D0 is used for a 32 bit return. */

INT32 temp = multiplicand*multiplier/divisor;
//printf("%d * %d / %d = %d\n",multiplicand,multiplier,divisor,temp);
return temp;
#ifndef mccabe
#pragma ASM

        tst.l   (S_divisor,A6)
        bne     sQWMD_Start

        move.l  #-1,d1
        bra     sQWMD_Done

sQWMD_Start
	move.l	(S_multiplicand,A6),D1
	muls.l	(S_multiplier,A6),D0:D1

	divs.l	(S_divisor,A6),D0:D1

        add.l   D0,D0                  ; mult remainder by 2
        divs.l  (S_divisor,A6),D0      ; divide, yeilding only quotient
        add.l   D1,D0                  ; round 

sQWMD_Done
*       move.l	d1,-(sp)               ; push result for debug reasons
*       move.l	(sp)+,d1               ; pop it back off


#pragma END_ASM
#endif
        
  (void)multiplicand;
  (void)multiplier;
  (void)divisor;
}


U_INT32 BoundsCheckedQWMD      ( U_INT32 multiplicand,
                                 U_INT32 multiplier,
                                 U_INT32 divisor,
                                 U_INT32 limit,
                                 BIT8    *overflow )
{

U_INT32 temp = multiplicand*multiplier/divisor;
printf("BoundsCheckedQWMD:%d * %d / %d = %d\n",multiplicand,multiplier,divisor,temp);
/* identical to return round( multiplicand*multiplier/divisor )
    however, this uses a 64 bit intermediate */

/* limit checked result and overflow checked divide */

/* according to the 68332 C Cross Compiler Reference Manual
   Section 3, page 3-18 (Register Usage)  D0,D1 are reserved
   for working registers, we can scribble them at will.  This
   section also indicates that D0 is used for a 32 bit return. */

#ifndef mccabe
#pragma ASM

        movea.l (S_overflow,A6),A0

        tst.l   (S_divisor,A6)
        beq     Overflow

	move.l	(S_multiplicand,A6),D1
	mulu.l	(S_multiplier,A6),D0:D1
	divu.l	(S_divisor,A6),D0:D1

        bvs     Overflow

        add.l   D0,D0                  ; mult remainder by 2
        divu.l  (S_divisor,A6),D0      ; divide, yeilding only quotient
        add.l   D1,D0                  ; round 

        cmp.l   (S_limit,A6),D0 
        bcc     Overflow

	move.l	d1,-(sp)               ; push result for debug reasons
	move.l	(sp)+,d1               ; pop it back off

        clr.b   (A0)                   ; indicate success
        bra     Continue

Overflow
        st.b    (A0)
        move.l  (S_limit,A6),D0        ; return the max value

Continue

#pragma END_ASM
#endif
        
  (void)multiplicand;
  (void)multiplier;
  (void)divisor;
  (void)limit;
  (void)overflow;
}

